package com.ruoyi.project.test.gds.formal;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.http.HttpUtil;
import com.google.common.collect.Lists;
import com.ruoyi.project.test.gds.formal.mapper.GdsFileMapper;
import com.ruoyi.project.test.gds.formal.mapper.ProcessDataMapper;
import com.ruoyi.project.test.gds.formal.mapper.ProcessInfoMapper;
import com.ruoyi.project.test.gds.formal.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicLong;

@Component
@Slf4j
public class GdsProcess {

    //8x8阵列
    public static final int SEGMENT = 8;
    //3x3步进
    public static final int STEP = 3;

    //8寸晶圆直径为20.32cm,203200microns
    public static final int DIAMETER = 203200;

    //8寸初始坐标
    public static final int INITX = -101600;
    public static final int INITY = 101600;

    @Autowired
    public GdsFileMapper gdsFileMapper;
    @Autowired
    public ProcessDataMapper processDataMapper;
    @Autowired
    public ProcessInfoMapper processInfoMapper;

    @Resource(name = "threadPoolTaskExecutor")
    public Executor asyncServiceExecutor;

    /**
     * 判断一个点是否在多边形内（特殊情况：要检测的点在多变形的一条边上，射线法判断的结果是不确定的，需要特殊处理）-判断点在多边形内-射线法
     * @param corners
     * @param xs
     * @param ys
     * @param x
     * @param y
     * @return
     */
    public static boolean pointInPolygon(int corners,int[] xs,int[] ys,int x,int y) {

        int   i,j=corners-1 ;
        boolean  result=false;

        for (i=0;i<corners; i++) {
            if((ys[i]< y && ys[j]>=y
                    ||   ys[j]<y && ys[i]>=y)
                    && (xs[i]<=x || xs[j]<=x)) {
                result^=(xs[i]+(y-ys[i])/(ys[j]-ys[i])*(xs[j]-xs[i])<x);}
            j=i;}

        return result; }

    /**
     * 叉积求点在线段上
     * @param px1
     * @param py1
     * @param px2
     * @param py2
     * @param qx
     * @param qy
     * @return
     */
    public static boolean onSegment(int px1 , int py1 ,int px2 , int py2, int qx,int qy)
    {
        if((qx - px1) * (py2 - py1) == (px2 - px1) * (qy - py1)  //叉乘
                //保证Q点坐标在pi,pj之间
                && Math.min(px1 , px2) <= qx && qx <= Math.max(px1 , px2)
                && Math.min(py1 , py2) <= qy && qy <= Math.max(py1 , py2))
            return true;
        else
            return false;
    }

    //并行版
    public void outputProcessData(ProcessInfo processInfo){

        //环境:8寸晶圆(200x200mm)，默认切割8x8阵列，3x3microns步进
        //默认已选取点数最多模块为判定模块
        //第一版直接判断光束和图形相交,以s型为加工路线
        int segment = NumberUtil.ceilDiv(processInfo.getDiameter(),processInfo.getSegment());//24500
        int step = NumberUtil.ceilDiv(segment,processInfo.getLight());//8467

        //根据fileId获取设计图形全部坐标集合
        GdsFile gdsFile = gdsFileMapper.selectGdsFileById(processInfo.getFileId());
        //选择图形最多结构作为对比
        GdsStructure gdsStructure = new GdsStructure();
        int graphCount = 0;
        for (int i = 0; i < gdsFile.getGdsStructures().size(); i++) {
            int count = gdsFile.getGdsStructures().get(i).getGdsGraphs().size();
            if (i==0){
                graphCount=count;
                gdsStructure= gdsFile.getGdsStructures().get(i);
            }
            if (count>graphCount){
                graphCount=count;
                gdsStructure= gdsFile.getGdsStructures().get(i);
            }
        }

        List<GdsGraph> graphs = gdsStructure.getGdsGraphs();
        List<ProcessInfo> processInfoList = Lists.newArrayList();

        int initx = -processInfo.getDiameter()/2;
        int inity = processInfo.getDiameter()/2;


        for (int i = 0; i < processInfo.getSegment(); i++) {
            for (int q = 0; q < processInfo.getSegment(); q++) {
                StringBuilder data = new StringBuilder();
                int light = processInfo.getLight();
                long processStep = processInfo.getStep();
                List<ProcessData> processDataList = Lists.newArrayList();
                ProcessInfo processInfo1 = new ProcessInfo();

                processInfo1.setId(IdUtil.getSnowflake().nextIdStr());
                processInfo1.setInitx(initx);
                processInfo1.setInity(inity);
                processInfo1.setIndex(q+1+i*processInfo.getSegment());

                int p1x=initx;
                int p1y=inity;
                int p2x=initx;
                int p2y=inity-light;
                int p3x=initx+light;
                int p3y=inity-light;
                int p4x=initx+light;
                int p4y=inity;

                log.info("模块开始执行："+System.currentTimeMillis());
                //获取加工数据
                for (int j = 0; j < step; j++) {
                    for (int k = 0; k < step; k++) {

                        //构建初始光束图形对象
                        GdsGraph lightGraph = new GdsGraph().setPoints(Arrays.asList(
                                new Point(p1x, p1y),
                                new Point(p2x, p2y),
                                new Point(p3x, p3y),
                                new Point(p4x, p4y)
                        ));
                        //这里还需优化
                        boolean compareResult = false;
                        for (GdsGraph compareGraph:
                                graphs) {
                            compareResult = PolygonIntersect.intersectionJudgment(lightGraph,compareGraph);
                            if (compareResult){
                                data.append("1");
                                break;
                            }
                        }
                        if (!compareResult){
                            data.append("0");
                        }

                        if (j%2==0){
                            //x 步进
                            p1x+=light;
                            p2x+=light;
                            p3x+=light;
                            p4x+=light;
                        }else {
                            //x 反步进
                            p1x-=light;
                            p2x-=light;
                            p3x-=light;
                            p4x-=light;
                        }
                        if ((k+1+(j)*step)%processStep==0) {
                            //满足加工分割步数新增
                            ProcessData processData = new ProcessData();
                                /*String id =  HttpUtil.get("http://localhost:9688/gds/getSnowflakeId");
                                processData.setId(id);*/
                            processData.setId(IdUtil.getSnowflake().nextIdStr());
                            processData.setIndex((k+1+(j)*step)/processStep);
//                                processData.setIndex(index.incrementAndGet());
                            processData.setInfoId(processInfo.getId());
                            processData.setDetail(data.toString());
                            processDataList.add(processData);
                            data=new StringBuilder();
                        }

                        if (processDataList.size()==100){
                            processDataMapper.batchInsert(processDataList);
                            processDataList.clear();
                        }
                    }
                    //y坐标下移一个light
                    p1y-=light;
                    p2y-=light;
                    p3y-=light;
                    p4y-=light;
                }
                processInfoList.add(processInfo);
                log.info("块处理结束："+processInfo.toString());
                if (q%2==0){
                    //x 步进
                    initx+=segment;
                }else {
                    //x 反步进
                    initx-=segment;
                }
            }
            inity-=segment;
        }
        processInfoMapper.batchInsert(processInfoList);
    }

    //并行版
    public void outputProcessData2(ProcessInfo processInfo){

        //环境:8寸晶圆(200x200mm)，默认切割8x8阵列，3x3microns步进
        //默认已选取点数最多模块为判定模块
        //第一版直接判断光束和图形相交,以s型为加工路线
        int segment = NumberUtil.ceilDiv(processInfo.getDiameter(),processInfo.getSegment());//24500
        int step = NumberUtil.ceilDiv(segment,processInfo.getLight());//8467

        //根据fileId获取设计图形全部坐标集合
        GdsFile gdsFile = gdsFileMapper.selectGdsFileById(processInfo.getFileId());
        //选择图形最多结构作为对比
        GdsStructure gdsStructure = new GdsStructure();
        int graphCount = 0;
        for (int i = 0; i < gdsFile.getGdsStructures().size(); i++) {
            int count = gdsFile.getGdsStructures().get(i).getGdsGraphs().size();
            if (i==0){
                graphCount=count;
                gdsStructure= gdsFile.getGdsStructures().get(i);
            }
            if (count>graphCount){
                graphCount=count;
                gdsStructure= gdsFile.getGdsStructures().get(i);
            }
        }

        List<GdsGraph> graphs = gdsStructure.getGdsGraphs();
        List<ProcessInfo> processInfoList = Lists.newArrayList();

        int initx = -processInfo.getDiameter()/2;
        int inity = processInfo.getDiameter()/2;

        for (int i = 0; i < processInfo.getSegment(); i++) {
            for (int q = 0; q < processInfo.getSegment(); q++) {
                ProcessInfo processInfo1 = new ProcessInfo();

                processInfo1.setDiameter(processInfo.getDiameter());
                processInfo1.setLight(processInfo.getLight());
                processInfo1.setSegment(processInfo.getSegment());
                processInfo1.setFileId(processInfo.getFileId());
                processInfo1.setId(IdUtil.getSnowflake().nextIdStr());
                processInfo1.setInitx(initx);
                processInfo1.setInity(inity);
                processInfo1.setIndex(q+1+(i)*processInfo.getSegment());
                processInfo1.setStep(processInfo.getStep());
                processInfoList.add(processInfo1);
                if (q%2==0){
                    //x 步进
                    initx+=segment;
                }else {
                    //x 反步进
                    initx-=segment;
                }
            }
            inity-=segment;
        }
        processInfoMapper.batchInsert(processInfoList);

        long processStep = processInfo.getStep();
        List<ProcessData> processDataList = Lists.newArrayList();

        for (ProcessInfo temp:
             processInfoList) {

            AtomicLong index = new AtomicLong(0);

            asyncServiceExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    StringBuilder data = new StringBuilder();
                    int light = temp.getLight();

                    int p1x=temp.getInitx();
                    int p1y=temp.getInity();
                    int p2x=temp.getInitx();
                    int p2y=temp.getInity()-light;
                    int p3x=temp.getInitx()+light;
                    int p3y=temp.getInity()-light;
                    int p4x=temp.getInitx()+light;
                    int p4y=temp.getInity();

                    log.info("模块开始执行："+System.currentTimeMillis());

                    //获取加工数据
                    for (int j = 0; j < step; j++) {
                        for (int k = 0; k < step; k++) {

                            //构建初始光束图形对象
                            GdsGraph lightGraph = new GdsGraph().setPoints(Arrays.asList(
                                    new Point(p1x, p1y),
                                    new Point(p2x, p2y),
                                    new Point(p3x, p3y),
                                    new Point(p4x, p4y)
                            ));
                            //这里还需优化
                            boolean compareResult = false;
                            for (GdsGraph compareGraph:
                                    graphs) {
                                compareResult = PolygonIntersect.intersectionJudgment(lightGraph,compareGraph);
                                if (compareResult){
                                    data.append("1");
                                    break;
                                }
                            }
                            if (!compareResult){
                                data.append("0");
                            }

                            if (j%2==0){
                                //x 步进
                                p1x+=light;
                                p2x+=light;
                                p3x+=light;
                                p4x+=light;
                            }else {
                                //x 反步进
                                p1x-=light;
                                p2x-=light;
                                p3x-=light;
                                p4x-=light;
                            }

                            if ((k+1+(j)*step)%processStep==0) {
                                //满足加工分割步数新增
                                ProcessData processData = new ProcessData();
                                /*String id =  HttpUtil.get("http://localhost:9688/gds/getSnowflakeId");
                                processData.setId(id);*/
                                processData.setId(IdUtil.getSnowflake((int)(Math.random()*(31-0+1)+0),(int)(Math.random()*(31-0+1)+0)).nextIdStr());
                                processData.setIndex((k+1+(j)*step)/processStep);
//                                processData.setIndex(index.incrementAndGet());
                                processData.setInfoId(temp.getId());
                                processData.setDetail(data.toString());
                                processDataList.add(processData);
                                data=new StringBuilder();
                            }

                            if (processDataList.size()==100){
                                processDataMapper.batchInsert(processDataList);
                                processDataList.clear();
                            }
                        }
                        //y坐标下移一个light
                        p1y-=light;
                        p2y-=light;
                        p3y-=light;
                        p4y-=light;
                    }

                    log.info("块处理结束："+processInfo.toString());
                }
            });
        }

    }

    public static void main(String[] args) {
        /*int[] xs={40000,40000,-40000,-40000,-39000,-39000,39000,39000,-40000,-40000};
        int[] ys={-40000,40000,40000,-39000,-39000,39000,39000,-39000,-39000,-40000};
        int x=-40000;
        int y=-16000;
        int corners=xs.length;
        System.out.println(pointInPolygon(corners,xs,ys,x,y));
        System.out.println(onSegment(-40000,40000,40000,40000,-23500,39500));*/
//        outputProcessData();
    }
}
